"""--------------------------------------------------------------------------------------------------
Filename:   controls.py
Author:     Ben Han (uha10@uclive.ac.nz) adapted by Chris Chester
Date:       4 September 2013
Description:
    Control panel for the plotting mode. 
    Provides controls for trials during live data acquisition and plotting.
--------------------------------------------------------------------------------------------------"""

import wx, sys

#===============================================================================
# CLASS: ControlPanel(wx.Frame)
#    This class is derived from wx.Panel and contains the controls for the plot
#         - BoundControlBox for Y axis options
#         - CheckboxPanel for display options
#         - ButtonPanel for control options (start/stop, menu)
#         - SerialPanel for serial port settings
#===============================================================================
class ControlPanel(wx.Frame):
    """ Main control panel for training modes
    """
    def __init__(self, app, parent=None, ID=-1, title="Control Panel"):
        '''
        ==============  =====================================
        **Arguments:**
        app               (MainApp) Main app class
        parent            (wx.frame) Window to use as the main
                          window
        ID                (int) ID for window
        title             (string) title to use for window
        ==============  =====================================
       '''
        
        wx.Frame.__init__(self, parent, ID, title, pos=(0,0), size=(600, 400))
        panel = wx.Panel(self, -1)
        self.app = panel.app = app
        
        ## initial value of y_axis_max read and set for plot
        self.ymax_ctrl = BoundControlBox(panel, -1, "Y max", app.cfg.y_axis_max_init)
        self.chkbx_ctrl = CheckboxPanel(panel, -1, "Display")
        self.but_ctrl = ButtonPanel(panel, -1)
        self.serial_ctrl = SerialPanel(panel, -1)

        #self.Bind(wx.EVT_RADIOBUTTON, self.on_radiobutton)

        # Create a box and sizer
        box = wx.StaticBox(panel, -1, "Control Panel")
        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)

        # Add controls to the sizer
        bwidth = 3
        sizer.Add(self.ymax_ctrl, border=bwidth, flag=wx.ALL | wx.EXPAND)
        sizer.Add(self.chkbx_ctrl, border=bwidth, flag=wx.ALL | wx.EXPAND)
        sizer.Add(self.serial_ctrl, border=bwidth, flag=wx.ALL | wx.EXPAND)
        sizer.Add(self.but_ctrl, border=bwidth, flag=wx.ALL | wx.EXPAND)

        panel.SetSizer(sizer)
        sizer.Fit(self)
                                
    def on_radiobutton(self, event):
        '''
        function for radiobutton action
        '''
        if event.GetId() == 1:
            self.app.sess_status.ymax_auto = True
        else:
            self.app.sess_status.ymax_auto = False


#===============================================================================
#  CLASS: BoundControlBox
#     This class is used for the y axis control on the main control panel.
#===============================================================================
class BoundControlBox(wx.Panel):
    """ A static box with a couple of radio buttons and a text
        box. Allows to switch between an automatic mode and a 
        manual mode to control the y-axis range maximum. The y-axis 
        minimum is always zero.
    """
    def __init__(self, parent, ID, label, initval):
        
        '''
        ==============  =====================================
        **Arguments:**
        parent            (wx.frame) Window to use as the main
                          window
        ID                (int) ID for window
        label             (string) label for box
        initval           (int) initial manual peak value
        ==============  =====================================
       '''
        wx.Panel.__init__(self, parent, ID)
        self.app = parent.app
        self.value = initval

        box = wx.StaticBox(self, -1, label)
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        self.radio_auto = wx.RadioButton(self, 1, label="Auto", style=wx.RB_GROUP)
        self.radio_manual = wx.RadioButton(self, -1, label="Manual")
        self.manual_text = wx.TextCtrl(self, -1, size=(35, -1), value=str(initval), style=wx.TE_PROCESS_ENTER)
        
        self.radio_auto.SetValue(True)
        self.app.sess_status.ymax_auto = True
        
        #self.manual_text.Enable(self.radio_manual.GetValue())
        
        manual_box = wx.BoxSizer(wx.HORIZONTAL)
        manual_box.Add(self.radio_manual, flag=wx.ALIGN_CENTER_VERTICAL)
        manual_box.Add(self.manual_text, flag=wx.ALIGN_CENTER_VERTICAL)
        
        self.Bind(wx.EVT_RADIOBUTTON, self.on_update_radio, self.radio_manual)
        self.Bind(wx.EVT_RADIOBUTTON, self.on_update_radio, self.radio_auto)
        self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter, self.manual_text)
                
        
        sizer.Add(self.radio_auto, 0, wx.ALL, 10)
        sizer.Add(manual_box, 0, wx.ALL, 10)
        
        self.SetSizer(sizer)
        sizer.Fit(self)             
        
        
    def on_update_radio(self, event):
        '''
        Function for radio button events
        '''
        self.manual_text.Enable(self.radio_manual.GetValue())
        self.radio_auto.SetValue(self.radio_auto.GetValue())
        
        # Set ymax_auto on
        self.app.sess_status.ymax_auto = self.radio_auto.GetValue()
        if self.radio_auto.GetValue():
            self.app.cfg.y_axis_max = self.app.cfg.ymax_auto_value # Reapply y auto max
            

    def on_text_enter(self, event):
        '''
        Function for if enter is hit in manual text entry
        '''
        value = self.manual_text.GetValue()
        self.app.cfg.y_axis_max = int(value)

    def is_auto(self):
        '''
        checks if auto radio button is checked
        '''
        return self.radio_auto.GetValue()

    def get_value(self):
        '''
        returns manual range value
        '''
        return self.value

    def set_value(self, newval):
        '''
        sets manual range value
        '''
        self.value = newval

    def set_auto(self, boo):
        '''
       sets auto radio button on
        '''
        self.radio_auto.SetValue(boo)


#===============================================================================
#  CLASS: CheckboxPanel
#     This class is used to select display options in the main control panel.
#===============================================================================
class CheckboxPanel(wx.Panel):
    def __init__(self, parent, ID, label):
        
        '''
        ==============  =====================================
        **Arguments:**
        parent            (wx.frame) Window to use as the main
                          window
        ID                (int) ID for window
        label             (string) label for box
        ==============  =====================================
        '''
        wx.Panel.__init__(self, parent, ID)
        self.app = parent.app

        box = wx.StaticBox(self, -1, label)
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        self.cb_grid = wx.CheckBox(self, -1, "Grid")
        self.cb_plot = wx.CheckBox(self, -1, "Plot")
        self.cb_time = wx.CheckBox(self, -1, "Time")
        self.cb_ampl = wx.CheckBox(self, -1, "Amplitude")

        self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_plot, self.cb_plot)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_time, self.cb_time)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_ampl, self.cb_ampl)

        
        sizer.Add(self.cb_grid, 0, wx.ALL, 5)
        sizer.Add(self.cb_plot, 0, wx.ALL, 5)
        sizer.Add(self.cb_time, 0, wx.ALL, 5)
        sizer.Add(self.cb_ampl, 0, wx.ALL, 5)
        
        self.__set_properties()

        self.SetSizer(sizer)
        sizer.Fit(self)

    def __set_properties(self):
        cfg = self.app.cfg
        self.cb_grid.SetValue(cfg.default_grid)
        self.cb_plot.SetValue(cfg.default_plot)
        self.cb_time.SetValue(cfg.default_time)
        self.cb_ampl.SetValue(cfg.default_ampl)
        
    def on_cb_grid(self, event):
        self.app.plot.dOpt.gridRBtn.setChecked(self.cb_grid.GetValue())
        self.app.plot.draw_grid(self.cb_grid.GetValue())
        

    def on_cb_plot(self, event):
        self.app.plot.dOpt.plotRBtn.setChecked(self.cb_plot.GetValue())
        self.app.plot.show_plot(self.cb_plot.GetValue())

    def on_cb_time(self, event):
        self.app.plot.dOpt.timeRBtn.setChecked(self.cb_time.GetValue())

    def on_cb_ampl(self, event):
        self.app.plot.dOpt.ampRBtn.setChecked(self.cb_ampl.GetValue())


#===============================================================================
#  CLASS: ButtonPanel
#     This class contains the control buttons which start and stop the trials
#===============================================================================
class ButtonPanel(wx.Panel):
    def __init__(self, parent, ID):
        '''
        ==============  =====================================
        **Arguments:**
        parent            (wx.frame) Window to use as the main
                          window
        ID                (int) ID for window
        ==============  =====================================
        '''
        wx.Panel.__init__(self, parent, ID)
        self.app = parent.app
        
        # Create buttons
        self.next_button = wx.Button(self, -1, "Start", )
        self.recalib_button = wx.Button(self, -1, "Re-calibrate")
        self.reset_button = wx.Button(self, -1, "Reset target to baseline")
        self.pause_button = wx.Button(self, -1, "Pause")
        self.save_button = wx.Button(self, -1, "Save and exit")
        self.menu_button = wx.Button(self, -1, "Exit to menu")
               
        # Sets handlers
        self.Bind(wx.EVT_BUTTON, self.app.phdls.next_button, self.next_button)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.recalibrate, self.recalib_button)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.target_reset, self.reset_button)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.pause, self.pause_button)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.save_exit, self.save_button)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.exit_plot, self.menu_button)
        
        self.__set_properties()
        self.__do_layout() 
        
    def __set_properties(self):
        self.next_button.Disable()
        self.next_button.SetMinSize((70, 23))
        self.recalib_button.Disable()
        self.recalib_button.SetMinSize((70, 23))
        self.reset_button.Disable()
        self.reset_button.SetMinSize((150, 23))
        self.save_button.Disable()
        self.save_button.SetMinSize((150, 23))
        self.pause_button.Disable()
        self.pause_button.SetMinSize((150, 23))
        self.menu_button.SetMinSize((150, 23))
        
    def __do_layout(self):
        # Add buttons to sizer
        sizer2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer2.Add(self.next_button, 0, wx.ALL | wx.CENTRE, 5)
        sizer2.Add(self.recalib_button, 0, wx.ALL | wx.CENTRE, 5)
        box = wx.StaticBox(self, -1, "Control")
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
        sizer.Add(sizer2, 0, wx.ALL, 5)
        sizer.Add(self.pause_button, 0, wx.ALL | wx.CENTRE, 5)
        sizer.AddSpacer(5)
        sizer.Add(self.reset_button, 0, wx.ALL | wx.CENTRE, 5)
        sizer.AddSpacer(5)
        sizer.Add(self.save_button, 0, wx.ALL | wx.CENTRE, 5)
        sizer.Add(self.menu_button, 0, wx.ALL | wx.CENTRE, 5)
        self.SetSizer(sizer)
        sizer.Fit(self)
        
    def enable_start(self, bool=True):
        '''
        Enables the start button
        '''
        self.next_button.Enable(bool)


#===============================================================================
# CLASS: SerialPanel
#    This class contains a control widget to set the port value of the 
#    serial console.
#===============================================================================    
class SerialPanel(wx.Panel):
    def __init__(self, parent, ID):
        '''
        ==============  =====================================
        **Arguments:**
        parent            (wx.frame) Window to use as the main
                          window
        ID                (int) ID for window
        ==============  =====================================
        '''
        wx.Panel.__init__(self, parent, ID)
        self.app = parent.app
        
        self.sizer_outer_box_staticbox = wx.StaticBox(self, -1, "Serial port control")
        self.button_connect = wx.Button(self, -1, "Connect")
        self.button_disconnect = wx.Button(self, -1, "Disconnect")

        self.Bind(wx.EVT_BUTTON, self.app.phdls.serial_connect, self.button_connect)
        self.Bind(wx.EVT_BUTTON, self.app.phdls.serial_disconnect, self.button_disconnect)
        
        self.__set_properties()
        self.__do_layout()

    def __set_properties(self):
        self.button_disconnect.Disable()

    def __do_layout(self):
        sizer_outer_box = wx.StaticBoxSizer(self.sizer_outer_box_staticbox, wx.VERTICAL)
        sizer_buttons = wx.GridSizer(1, 2, 0, 0)
        sizer_port_select = wx.BoxSizer(wx.HORIZONTAL)
        sizer_outer_box.Add(sizer_port_select, 1, wx.EXPAND, 0)
        sizer_buttons.Add(self.button_connect, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5)
        sizer_buttons.Add(self.button_disconnect, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5)
        sizer_outer_box.Add(sizer_buttons, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_outer_box)
        sizer_outer_box.Fit(self)
        
        
# End of controls.py